// PlotDialog.cpp
// Spectral Processing dialog using Qt4 and Qwt packages
// Author: Garreth Ruane June 2011
// File reading routine based on work of Gary Hoffman 10-04-2004

#include <QtGui>
#include "include/PlotDialog.h"
#include "include/readSpectrumFile.h"
#include "include/bandprocessing.h"
const int MAX_NUMBER_OF_BANDS = 50;


// PlotDialog Constructor
PlotDialog::PlotDialog(QWidget *parent)
	: QDialog(parent,Qt::Window)
{
	this->setWindowTitle("Band Analysis");

	// Initialize GUI Widgets
	menubar = new QMenuBar(0);
	filemenu = new QMenu("File");
	optionsmenu = new QMenu("Options");
	viewmenu = new QMenu("View");
	
	cpointsaction = new QAction("Enable Continuum Point Markers",this);
	cpointsaction->setCheckable(true);
	cpointsaction->setChecked(true);
	
	bandcenterlineaction = new QAction("Show Band Minimum Line",this);
	bandcenterlineaction->setCheckable(true);
	bandcenterlineaction->setChecked(true);
	
	actualminaction = new QAction("Show Actual Mininum Marker",this);
	actualminaction->setCheckable(true);
	actualminaction->setChecked(true);
	
	resetaxesaction = new QAction("Reset Axes",this);
	viewmenu->addAction(resetaxesaction);
	
	quitaction = new QAction("Quit",this);
	filemenu->addAction(quitaction);
	
	optionsmenu->addAction(cpointsaction);
	optionsmenu->addAction(bandcenterlineaction);	
	optionsmenu->addAction(actualminaction);
		
	menubar->addMenu(filemenu);	
	menubar->addMenu(optionsmenu);	
	menubar->addMenu(viewmenu);
	
	plot = new QwtPlot;
	data = new QwtPlotCurve;
	rcdata = new QwtPlotCurve;
	
	data->setVisible(false);
	rcdata->setVisible(false);
	
	pcanvas = plot->canvas();
	ppicker = new QwtPlotPicker(pcanvas);
	ppicker->setTrackerMode(QwtPicker::AlwaysOn);
	ppicker->setRubberBand(QwtPicker::VLineRubberBand);
	ppicker->setStateMachine(new QwtPickerClickPointMachine);
	ppicker->setTrackerPen(QColor(Qt::lightGray));
	ppicker->setEnabled(false);
	
	pzoomer = new QwtPlotZoomer(pcanvas);
	pzoomer->setMaxStackDepth(-1);
	
	marker1 = new QwtPlotMarker;
	marker2 = new QwtPlotMarker;
	marker3 = new QwtPlotMarker;
	marker4 = new QwtPlotMarker;
	contline = new QwtPlotMarker;
	contmarker1 = new QwtPlotMarker;
	contmarker2 = new QwtPlotMarker;
	bandcenterline = new QwtPlotMarker;
	actualminmarker = new QwtPlotMarker;
	
	marker1->setSymbol(new QwtSymbol(QwtSymbol::VLine, QBrush(Qt::darkRed), QPen(Qt::red, 1, Qt::DotLine), QSize(1000,1000)));
	marker2->setSymbol(new QwtSymbol(QwtSymbol::VLine, QBrush(Qt::darkRed), QPen(Qt::red, 1, Qt::DotLine), QSize(1000,1000)));
	marker3->setSymbol(new QwtSymbol(QwtSymbol::VLine, QBrush(Qt::darkBlue), QPen(Qt::blue, 1, Qt::DotLine), QSize(1000,1000)));
	marker4->setSymbol(new QwtSymbol(QwtSymbol::VLine, QBrush(Qt::darkBlue), QPen(Qt::blue, 1, Qt::DotLine), QSize(1000,1000)));
	contline->setSymbol(new QwtSymbol(QwtSymbol::HLine, QBrush(Qt::darkGreen), QPen(Qt::darkGreen, 1, Qt::DashLine), QSize(5000,5000)));
	
	contmarker1->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, QBrush(Qt::NoBrush), QPen(Qt::red, 1, Qt::SolidLine), QSize(8,8)));
	contmarker2->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, QBrush(Qt::NoBrush), QPen(Qt::blue, 1, Qt::SolidLine), QSize(8,8)));

	bandcenterline->setSymbol(new QwtSymbol(QwtSymbol::VLine, QBrush(Qt::darkBlue), QPen(Qt::magenta, 1, Qt::DotLine), QSize(1000,1000)));
	
	actualminmarker->setSymbol(new QwtSymbol(QwtSymbol::DTriangle, QBrush(Qt::NoBrush), QPen(Qt::magenta, 1, Qt::SolidLine), QSize(8,8)));
	
	marker1->attach(plot);
	marker2->attach(plot);
	marker3->attach(plot);
	marker4->attach(plot);
	contline->attach(plot);
	contmarker1->attach(plot);
	contmarker2->attach(plot);
	bandcenterline->attach(plot);
	actualminmarker->attach(plot);
	
	marker1->setVisible(false);
	marker2->setVisible(false);
	marker3->setVisible(false);
	marker4->setVisible(false);
	contline->setVisible(false);
	contmarker1->setVisible(false);
	contmarker2->setVisible(false);	
	bandcenterline->setVisible(false);	
	actualminmarker->setVisible(false);	
	
	cpointmarkers = true;
	showbandcenterline = true; 
	showactualminmarker = true;
	

	filedialog = new QFileDialog;
	savedialog = new QFileDialog;
	spinbox1 = new QDoubleSpinBox;
	spinbox2 = new QDoubleSpinBox;
	spinbox3 = new QDoubleSpinBox;
	spinbox4 = new QDoubleSpinBox;
	entry = new QTextEdit;
	display = new QPlainTextEdit;
	strdisplay = new QString;
	strbandmin = new QString;
	strbanddepth = new QString;
	strfwhm = new QString;
	strasym = new QString;
	strutil = new QString;
	browsebutton = new QPushButton("Browse");
	rcbutton = new QPushButton("Remove Continuum");
	calcbutton = new QPushButton("Calculate");
	clearbutton = new QPushButton("Clear Input");
	clearoutputbutton = new QPushButton("Clear Output");
	plotdatatofilebutton = new QPushButton("Export Plot Data");
	tofilebutton = new QPushButton("Export Output");
	tostdoutbutton = new QPushButton("Print to Standard Output");
	resetbutton = new QPushButton("Reset All");
	inputfilelabel = new QLabel("Input File: ");
	inputfilelineedit = new QLineEdit;
	inputfileloadbutton = new QPushButton("Load");
	radiolabel = new QLabel("Continuum: ");
	pointsradiobutton = new QRadioButton("Points");
	rangesradiobutton = new QRadioButton("Ranges");
	selectbox = new QCheckBox("Select Continuum (Zoom = Off)");
	inputlabel = new QLabel("Input: ");
	outputlabel = new QLabel("Output: ");
	font = new QFont;

	data->setRenderHint(QwtPlotItem::RenderAntialiased);
	//rcdata->setRenderHint(QwtPlotItem::RenderAntialiased);

	font->setStyleHint(QFont::System);
	font->setPointSize(10);
	
	entry->setFixedHeight(25);
	entry->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	entry->setMinimumWidth(250);
	
	display->setReadOnly(true);
	display->setMinimumHeight(100);

	pointsradiobutton->toggle();
	clearbutton->setEnabled(false);
	resetbutton->setEnabled(false);
	calcbutton->setEnabled(false);
 	rcbutton->setEnabled(false);
 	clearoutputbutton->setEnabled(false);
 	plotdatatofilebutton->setEnabled(false);
 	tofilebutton->setEnabled(false);
 	tostdoutbutton->setEnabled(false);
 	
 	filedialog->setFileMode(QFileDialog::AnyFile);
 	filedialog->setViewMode(QFileDialog::Detail);
 	
 	savedialog->setFileMode(QFileDialog::AnyFile);
 	savedialog->setViewMode(QFileDialog::Detail);
 	savedialog->setAcceptMode(QFileDialog::AcceptSave);
 	
	plot->setAxisScale(QwtPlot::yLeft,spinbox2->value(),spinbox1->value());
	plot->setAxisScale(QwtPlot::xBottom,spinbox3->value(),spinbox4->value());
	plot->setCanvasBackground(QColor(Qt::white));
	xlabel = new QwtText("Wavelength (microns)"); 
	xlabel->setFont(*font);
	plot->setAxisTitle(QwtPlot::xBottom,*xlabel);


	usingranges = 0;
	xmin = 0; xmax = 0; ymin = 0; ymax = 0;
	
	// Set up Layouts
	QVBoxLayout *window = new QVBoxLayout;
	
	QHBoxLayout *toppart = new QHBoxLayout;
	QHBoxLayout *plotarea = new QHBoxLayout;
	
	QVBoxLayout *ioarea = new QVBoxLayout;
	QVBoxLayout *ioarea2 = new QVBoxLayout;
	QHBoxLayout *radioarea = new QHBoxLayout;
	QHBoxLayout *inputarea = new QHBoxLayout;
	QVBoxLayout *radioarea2 = new QVBoxLayout;
	QHBoxLayout *calcbuttonarea = new QHBoxLayout;
	QHBoxLayout *xspinboxlayout = new QHBoxLayout;
	QVBoxLayout *yspinboxlayout = new QVBoxLayout;
	QVBoxLayout *rightsideplotarea = new QVBoxLayout;
	QHBoxLayout *buttonarea = new QHBoxLayout;
	
	toppart->addWidget(inputfilelabel);
	toppart->addWidget(inputfilelineedit);
	toppart->addWidget(browsebutton);
	toppart->addWidget(inputfileloadbutton);
	
	yspinboxlayout->addWidget(spinbox1);
	yspinboxlayout->addSpacing(250);
	yspinboxlayout->addStretch(1);
	yspinboxlayout->addWidget(spinbox2);
	yspinboxlayout->addSpacing(40);
	
	xspinboxlayout->addWidget(spinbox3);
	xspinboxlayout->addStretch(1);
	xspinboxlayout->addWidget(spinbox4);
	
	rightsideplotarea->addWidget(plot);
	rightsideplotarea->addSpacing(-25);
	rightsideplotarea->addLayout(xspinboxlayout);
	plotarea->addLayout(yspinboxlayout);
	plotarea->addLayout(rightsideplotarea);
	
	radioarea->addWidget(radiolabel);
	radioarea->addWidget(pointsradiobutton);
	radioarea->addWidget(rangesradiobutton);
	radioarea->addWidget(selectbox);
	radioarea->addStretch(1);	
	radioarea->addWidget(plotdatatofilebutton);
	
	inputarea->addWidget(inputlabel);
	inputarea->addWidget(entry);
	inputarea->addWidget(clearbutton);
	//inputarea->addStretch(1);
	inputarea->addWidget(rcbutton);
	inputarea->addWidget(calcbutton);
		
	radioarea2->addLayout(radioarea);
	radioarea2->addLayout(inputarea);
	radioarea2->addLayout(calcbuttonarea);

	buttonarea->addStretch(1);
	buttonarea->addWidget(clearoutputbutton);
	buttonarea->addWidget(tostdoutbutton);
	buttonarea->addWidget(tofilebutton);
	buttonarea->addWidget(resetbutton);
	
	ioarea2->addWidget(outputlabel);
	//ioarea2->addSpacing(5);
	ioarea2->addWidget(display);
	
	ioarea->addLayout(radioarea2);
	ioarea->addLayout(ioarea2);
	ioarea->addLayout(buttonarea);
	
	window->setMenuBar(menubar);
	window->addLayout(toppart);
	window->addLayout(plotarea);
	window->addLayout(ioarea);
	
	setLayout(window);
	
	
	// Connect SIGNALS and SLOTS
	connect(spinbox1, SIGNAL(valueChanged(double)),this,SLOT(updateAxis()));
	connect(spinbox2, SIGNAL(valueChanged(double)),this,SLOT(updateAxis()));
	connect(spinbox3, SIGNAL(valueChanged(double)),this,SLOT(updateAxis()));
	connect(spinbox4, SIGNAL(valueChanged(double)),this,SLOT(updateAxis()));
	connect(pzoomer, SIGNAL( zoomed(const QRectF &) ), this, SLOT( updateAfterZoom(const QRectF &) ) );
	connect(inputfileloadbutton, SIGNAL(clicked()),this,SLOT(loadfile()));
	connect(resetbutton, SIGNAL(clicked()),this,SLOT(reset()));
	connect(resetaxesaction, SIGNAL(triggered()),this,SLOT(resetaxes()));
	connect(rcbutton, SIGNAL(clicked()),this,SLOT(removecontinuum()));
	connect(pointsradiobutton,SIGNAL(toggled(bool)),this,SLOT(usepoints(bool)));
	connect(rangesradiobutton,SIGNAL(toggled(bool)),this,SLOT(useranges(bool)));
	connect(selectbox,SIGNAL(toggled(bool)),this,SLOT(usemouse(bool)));
	connect(browsebutton,SIGNAL(clicked()),this,SLOT(browse()));
	connect(calcbutton, SIGNAL(clicked()),this,SLOT(calculate()));
	connect(ppicker,SIGNAL(selected(const QPointF &)),this,SLOT(pointRegister(const QPointF &)));
	connect(tostdoutbutton, SIGNAL(clicked()),this,SLOT(printtostd()));
	connect(plotdatatofilebutton, SIGNAL(clicked()),this,SLOT(printPlotDataToFile()));
	connect(tofilebutton, SIGNAL(clicked()),this,SLOT(printtofile()));
	connect(clearbutton, SIGNAL(clicked()),this,SLOT(cleartext()));
	connect(clearoutputbutton, SIGNAL(clicked()),this,SLOT(clearoutput()));
	connect(cpointsaction, SIGNAL(toggled(bool)),this,SLOT(enablecpointmarkers(bool)));
	connect(bandcenterlineaction, SIGNAL(toggled(bool)),this,SLOT(enablebandcenterline(bool)));
	connect(actualminaction, SIGNAL(toggled(bool)),this,SLOT(enableactualminmarker(bool)));
	connect(quitaction, SIGNAL(triggered()),this,SLOT(quit()));

}


// Updates the axis boundaries
void PlotDialog::updateAxis()
{
	plot->setAxisScale(QwtPlot::yLeft,spinbox2->value(),spinbox1->value());
	plot->setAxisScale(QwtPlot::xBottom,spinbox3->value(),spinbox4->value());
	plot->replot();
}

// Updates the spin boxes after zoom with mouse
void PlotDialog::updateAfterZoom(const QRectF &rect)
{
	double x1,x2,y1,y2,tmp;
	x1 = rect.left();
	x2 = rect.right();
	y1 = rect.bottom();
	y2 = rect.top();
	
	if(x1 > x2)
	{
		tmp = x1;
		x1 = x2;
		x2 = tmp;
	}
	
	if(y1 > y2)
	{
		tmp = y1;
		y1 = y2;
		y2 = tmp;
	}
	
	spinbox1->setValue(y2);
 	spinbox2->setValue(y1);   
 	spinbox3->setValue(x1);
 	spinbox4->setValue(x2);  
}

// Reads the selected input file into w,d, and e vectors corresponding to wavelengths, data, and possibly error if necessary. 
// Routine written by Gary Hoffman
void PlotDialog::loadfile()
{
	// If something is plotted, get rid of it. 

	data->setVisible(false);
	rcdata->setVisible(false);

	contline->setVisible(false);
	bandcenterline->setVisible(false);
	actualminmarker->setVisible(false);
			
	// Read the input file line and convert it to a c-style string.
	QString str = inputfilelineedit->text();
	QByteArray ba = str.toLocal8Bit();
	filename = ba.data();

	// If the input is empty to nothing.
	if(str.isEmpty())
		return;

	
    double c1,c2,c3,c4,	// placeholders for lines of data in file.
    		w1 = 0,d1 = 0; 
    char ch;			// single character storage
    int index = 0;		// index for counting lines
		
    ymin = 999999999;	// Initialize the maximum and minimum data value. 
	ymax = 0;
	
	// Clear vectors
	w.clear();
	d.clear();
	e.clear();
	
	// Check if file is a directory or not a "regular file"
	if(stat(filename,&stats) == 0)
	{
		if(stats.st_mode & S_IFDIR)
		{
			QMessageBox msg;
			msg.setText("Error reading file");
			msg.setInformativeText("File is a directory.");
			msg.exec();
			return;
		}
		else if(!(stats.st_mode & S_IFREG))
		{
			QMessageBox msg;
			msg.setText("Error reading file");
			msg.setInformativeText("Unknown file type.");
			msg.exec();
			return;			
		}
	}
	
	// Open filestream
	ifstream fs;
	try{fs.open(filename);}
	catch(...)
	{
		QMessageBox msg;
		msg.setText("Error reading file");
		msg.setInformativeText("File not found.");
		msg.exec();
		fs.close();
		return;
	}

    //if this fails, print error message and return
    
    // count the number of channels in the file. 
    numOfChannels = countChannels(filename);

    if( !fs )
    {    
    	QMessageBox msg;
		msg.setText("Error reading file");
		msg.setInformativeText("File not found.");
		msg.exec();
		fs.close();
		return;
    } 
    //otherwise while file input is successful, process data
    else
    {       	
    	//examine first non-white space character
    	try
    	{
			fs >> ch;
		}
		catch(...)
		{
			QMessageBox msg;
			msg.setText("Error reading file");
			msg.setInformativeText("File not found.");
			msg.exec();
			fs.close();
			return;
		}
        while( fs.good() && !fs.eof() && fs && (index < numOfChannels))
        {    
			//if the character stored in ch is not a digit
			//then put it back in the input stream and 
			//ignore the rest of the line
			if( (ch < '0') || (ch > '9') )
			{    
				fs.putback( ch );
				while ((ch != '\n') && (ch != '\r') )
					ch = fs.get();		
				fs.putback( ch );
			} 

			//otherwise put the character back in the input stream and read data into wavelength. Look for the next number. 
			else
			{
				fs.putback( ch );
				fs >> c1;
				w.push_back(c1);
				
				// Check in next non-white space char
				fs >> ch;
				
				// handle delimeters.
				while (ch == ',' || ch == ';' )
					fs >> ch;

				if( ((ch < '0') || (ch > '9')) && ch != '-' )
				{
					fs.putback( ch );
					while ((ch != '\n') && (ch != '\r'))
						ch = fs.get();
					fs.putback( ch );
					w.clear();
					d.clear();
					e.clear();
				}
				else
				{
					fs.putback( ch );
					fs >> c2;
					d.push_back(c2);
					
					if(index == 0)
					{
						w1 = w.front();
						d1 = d.front();
					}
				
					//determine if additional data are present
					//if the next character is not newline then assume
					//there is another column of data representing error
					ch = fs.get();
		
					//check for white space at end of line
					if( ch == ',' || ch == ';' || ch == ' ' )
					{
						while (ch == ',' || ch == ';' || ch == ' ')
							ch = fs.get();
					}
					//put back the last character
					fs.putback( ch );

					if( ch != '\n' && ch != '\r' )
					{
						fs >> c3;
						e.push_back(c3);
					}

					// Check if the first column may be a wavenumber column
					// and then check if there is a fourth column
					if( fabs( c1 * c2 / 10000 - 1 ) < 0.00001)
					{
						ch = fs.get();
		
						//check for white space at end of line
						if( ch == ',' || ch == ';' || ch == ' ' )
						{
							while (ch == ',' || ch == ';' || ch == ' ')
								ch = fs.get();
						}
						//put back the last character
						fs.putback( ch );

						if( ch != '\n' && ch != '\r')
						{
							if(w1 > d1)
								w.at(index) = d.at(index);
							d.at(index) = e.at(index);
							fs >> c4;
							e.at(index) = c4;
							xlabel->setText("Wavelength (microns)"); 
							plot->setAxisTitle(QwtPlot::xBottom,*xlabel);	
						}

					}//if
					else if(fabs( c1 * c2 / 10000000 - 1 ) < 0.00001)
					{
						ch = fs.get();
		
						//check for white space at end of line
						if( ch == ',' || ch == ';' || ch == ' ' )
						{
							while (ch == ',' || ch == ';' || ch == ' ')
								ch = fs.get();
						}
						//put back the last character
						fs.putback( ch );

						if( ch != '\n' && ch != '\r')
						{
							if(w1 > d1)
								w.at(index) = d.at(index);
							d.at(index) = e.at(index);
							fs >> c4;
							e.at(index) = c4;					
							xlabel->setText("Wavelength (nm)"); 
							plot->setAxisTitle(QwtPlot::xBottom,*xlabel);
						}


					}//else if
					else if(fabs( c1 * c2 / 100000000 - 1 ) < 0.00001)
					{
						ch = fs.get();
		
						//check for white space at end of line
						if( ch == ',' || ch == ';' || ch == ' ' )
						{
							while (ch == ',' || ch == ';' || ch == ' ')
								ch = fs.get();
						}
						//put back the last character
						fs.putback( ch );

						if( ch != '\n' && ch != '\r')
						{
							if(w1 > d1)
								w.at(index) = d.at(index);
							d.at(index) = e.at(index);
							fs >> c4;
							e.at(index) = c4;					
							xlabel->setText("Wavelength (Angstroms)"); 
							plot->setAxisTitle(QwtPlot::xBottom,*xlabel);
						}


					}//else if
					else
					{
						xlabel->setText("Wavelength (microns)"); 
						plot->setAxisTitle(QwtPlot::xBottom,*xlabel);	
					}
					// Keep maximum and minimum
					if(d.at(index) > ymax)
						ymax = d.at(index);
					else if( d.at(index) < ymin )
						ymin = d.at(index);
					//ignore the rest of the line
					while ((ch != '\n') && (ch != '\r'))
						ch = fs.get();
					fs.putback(ch);
					
					index++;
				
				} //else
			}//else
			
			//examine first non-white space character of next line
			fs >> ch;
			
		} //while
    } //else
    
	fs.close();

	xmin = w.front();
	xmax = w.back();

	if(xmax > 1000)
	{
		xlabel->setText("Wave Number (1/cm)"); 
		plot->setAxisTitle(QwtPlot::xBottom,*xlabel);
	}
	
	// Set the axis ranges to appropriate values.
	spinbox1->setRange(ymin - 0.2*ymin,ymax + 0.2*ymax);
 	spinbox2->setRange(ymin - 0.2*ymin,ymax + 0.2*ymax);  
 	spinbox3->setRange(xmin - 0.2*xmin,xmax + 0.2*xmax);
 	spinbox4->setRange(xmin - 0.2*xmin,xmax + 0.2*xmax);
 	
 	spinbox1->setSingleStep((ymax - ymin)/100.0);
 	spinbox2->setSingleStep((ymax - ymin)/100.0);  
 	spinbox3->setSingleStep((xmax - xmin)/100.0);
 	spinbox4->setSingleStep((xmax - xmin)/100.0);  
 	
	spinbox1->setValue(ymax);
 	spinbox2->setValue(ymin);   
 	spinbox3->setValue(xmin);
 	spinbox4->setValue(xmax);  
 	
 	// Set the curve object to data and plot.
	data->setSamples(&w[0],&d[0],numOfChannels);
	data->attach(plot);  
	data->setVisible(true);  
	plot->replot();
	
	pzoomer->setZoomBase();
	
	// Enable buttons
	//inputfileloadbutton->setEnabled(false);
	clearbutton->setEnabled(true);
	resetbutton->setEnabled(true);
	calcbutton->setEnabled(true);
 	rcbutton->setEnabled(true);
 	clearoutputbutton->setEnabled(true);
 	tofilebutton->setEnabled(true);
 	plotdatatofilebutton->setEnabled(true);
 	tostdoutbutton->setEnabled(true);
 	
 	cleartext();
}

// Signal for radio button indicating continuum points opposed to ranges.
void PlotDialog::usepoints(bool checked)
{
	if(checked)
		usingranges = 0;
	cleartext();
}

// Signal for radio button indicating continuum ranges opposed to points.
void PlotDialog::useranges(bool checked)
{
	if(checked)
		usingranges = 1;
	cleartext();
}

// Signal for "Select Continuum" checkbox.
void PlotDialog::usemouse(bool checked)
{
	ppicker->setEnabled(checked);
	pzoomer->setEnabled(!checked);
}

// Signal for "Enable Continuum Point Markers" checkbox.
void PlotDialog::enablecpointmarkers(bool checked)
{
	cpointmarkers = checked;
	contmarker1->setVisible(checked);
	contmarker2->setVisible(checked);
	if(data->isVisible() || rcdata->isVisible())
		plot->replot();
}

// Signal for "Enable band center line" checkbox.
void PlotDialog::enablebandcenterline(bool checked)
{
	showbandcenterline = checked;
	bandcenterline->setVisible(checked);
	if(data->isVisible() || rcdata->isVisible())
		plot->replot();
}

// Signal for "Enable Actual min marker" checkbox.
void PlotDialog::enableactualminmarker(bool checked)
{
	showactualminmarker = checked;
	actualminmarker->setVisible(checked);
	if(data->isVisible() || rcdata->isVisible())
		plot->replot();
}

// Signal for browse button. 
void PlotDialog::browse()
{
	QStringList fileNames;
	filedialog->show();
	 
	if (filedialog->exec())
	{
		fileNames = filedialog->selectedFiles();
		inputfilelineedit->clear();	 
		inputfilelineedit->setText(fileNames.at(0));
	}
	loadfile();
}

// Removes the continuum and plots the band 
void PlotDialog::removecontinuum()
{
	// If something is plotted, get rid of it. 

	data->setVisible(false);
	rcdata->setVisible(false);

	bandcenterline->setVisible(false);
	actualminmarker->setVisible(false);
		
	QString str;
	str = entry->toPlainText();

	if(str.isEmpty())
		return;
	else
	{


	QStringList list = str.split(",", QString::SkipEmptyParts);
	
	newd.clear();
	
	// Read in continuum points or ranges
	int i = 0, numChan = w.size();
	double lowerb1 = 0, upperb1 = 0, lowerb2 = 0, upperb2 = 0;

	while(i < list.size())
	{
		if(list.size() % 2 != 0)
		{
			QMessageBox msg;
			msg.setText("Error");
			msg.setInformativeText("Odd number of continuum points.");
			msg.exec();
			loadfile();
			return;
		}
		if(usingranges == 0)
		{
			if(list.at(i).toDouble() != 0 && list.at(i+1).toDouble() != 0)
			{
				lowerb1 = (list.at(i)).toDouble();
				upperb1 = (list.at(i+1)).toDouble();
				i+=2;
			}
			else
			{
				// This shouldn't happen. 
				printf("Bad arguments!\n ");
				return;
			}

		}
		else
		{
			if(list.at(i).toDouble() != 0 && list.at(i+1).toDouble() != 0 && list.at(i+2).toDouble() != 0 && list.at(i+3).toDouble() != 0)
			{
				lowerb1 = list.at(i).toDouble();
				upperb1 = list.at(i+1).toDouble();
				lowerb2 = list.at(i+2).toDouble();
				upperb2 = list.at(i+3).toDouble();
				i+=4;
			}
			else
			{
				// This shouldn't happen. 
				printf("Bad arguments!\n ");
				return;
			}
		}
	}
	
	if(usingranges == 0)
	{
		int loweri = 0, upperi = 0;			
		double w1,w2,d1,d2,slope;
		double diff, mindiff;
		
		mindiff = fabs(w.at(0) - lowerb1);
		for( i = 1; i < numChan; i++)
		{
			diff = fabs(w.at(i) - lowerb1);
			if(diff < mindiff)
			{
				mindiff = diff;
				loweri = i;
			}
		}

		mindiff = fabs(w.at(0) - upperb1);
		for( i = 1; i < numChan; i++)
		{
			diff = fabs(w.at(i) - upperb1);
			if(diff < mindiff)
			{
				mindiff = diff;
				upperi = i;
			}
		}
		
		if(loweri >= upperi)
			return;
		
		w1 = w.at(loweri);
		w2 = w.at(upperi);
		d1 = d.at(loweri);
		d2 = d.at(upperi);
		slope = (d2 - d1)/(w2 - w1);
		for(i = 0; i < numChan; i++)
		{
			newd.push_back(d.at(i)/(slope*(w.at(i) - w1) + d1));
		}
		
		minrcx = w.front();
		minrc = newd.at(loweri);
		maxrc = newd.at(loweri);
		for(i = loweri+1; i <= upperi; i++)
		{
			if( newd.at(i) < minrc )
			{
				minrcx= w.at(i);
				minrc = newd.at(i);
			}
			if( newd.at(i) > maxrc )
				maxrc = newd.at(i);
		}

		marker1->setValue(w.at(loweri),newd.at(loweri));
		marker1->setVisible(true);
		
		contmarker1->setValue(w.at(loweri),newd.at(loweri));
		if( cpointmarkers )
			contmarker1->setVisible(true);
		else
			contmarker1->setVisible(false);
			
		marker2->setVisible(false);

		marker3->setValue(w.at(upperi),newd.at(upperi));
		marker3->setVisible(true);
		contmarker2->setValue(w.at(upperi),newd.at(upperi));
		if( cpointmarkers )
			contmarker2->setVisible(true);
		else
			contmarker2->setVisible(false);
			
		marker4->setVisible(false);
		
		contline->setValue(w.at(upperi),1.0);

	}	
	else
	{
		int lowerb1i = 0, upperb1i = 0, lowerb2i = 0, upperb2i = 0;
		int lowerCpointi, upperCpointi;
		double lowerCval, upperCval;			
		double w1,w2,d1,d2,slope;
		double diff, mindiff;
		int count,j;
		
		// Match passed values to nearest channels 
		mindiff = fabs(w.at(0) - lowerb1);
		for( i = 1; i < numChan; i++)
		{
			diff = fabs(w.at(i) - lowerb1);
			if(diff < mindiff)
			{
				mindiff = diff;
				lowerb1i = i;
			}
		}

		mindiff = fabs(w.at(0) - upperb1);
		for( i = 1; i < numChan; i++)
		{
			diff = fabs(w.at(i) - upperb1);
			if(diff < mindiff)
			{
				mindiff = diff;
				upperb1i = i;
			}
		}
		
		mindiff = fabs(w.at(0) - lowerb2);
		for( i = 1; i < w.size(); i++)
		{
			diff = fabs(w.at(i) - lowerb2);
			if(diff < mindiff)
			{
				mindiff = diff;
				lowerb2i = i;
			}
		}

		mindiff = fabs(w.at(0) - upperb2);
		for( i = 1; i < numChan; i++)
		{
			diff = fabs(w.at(i) - upperb2);
			if(diff < mindiff)
			{
				mindiff = diff;
				upperb2i = i;
			}
		}

		lowerCpointi = (lowerb1i + upperb1i) / 2;
		upperCpointi = (lowerb2i + upperb2i) / 2;
		
		if(upperCpointi <= lowerCpointi)
			return;
		
		// If the average is in between two channels, take the outer one.
		if( (lowerb2i + upperb2i) % 2 != 0 )
		{
			upperCpointi += 1;
		}
		
			
		// Find the average y-val and assign it to cval.
		count = 0; 	
		lowerCval = 0;
		for( j = lowerb1i; j <= upperb1i; j++ )
		{
			lowerCval += d.at(j);
			count++;
		}
		lowerCval /= count;
		
		count = 0; 	
		upperCval = 0;
		for( j = lowerb2i; j <= upperb2i; j++ )
		{
			upperCval += d.at(j);
			count++;
		}
		upperCval /= count;
		
		
		w1 = w.at(lowerCpointi);
		w2 = w.at(upperCpointi);
		d1 = lowerCval;
		d2 = upperCval;
		slope = (d2 - d1)/(w2 - w1);
		for(i = 0; i < numChan; i++)
		{
			newd.push_back(d.at(i)/(slope*(w.at(i) - w1) + d1));
		}
		
		minrcx = w.front();
		minrc = newd.at(lowerCpointi);
		maxrc = newd.at(lowerCpointi);
		for(i = lowerCpointi+1; i <= upperCpointi; i++)
		{
			if( newd.at(i) < minrc )
			{
				minrcx= w.at(i);
				minrc = newd.at(i);
			}
			if( newd.at(i) > maxrc )
				maxrc = newd.at(i);
		}
		
		
		contmarker1->setValue(w.at(lowerCpointi),newd.at(lowerCpointi));
		if( cpointmarkers )
			contmarker1->setVisible(true);
		else
			contmarker1->setVisible(false);

		
		contmarker2->setValue(w.at(upperCpointi),newd.at(upperCpointi));
		if( cpointmarkers )
			contmarker2->setVisible(true);
		else
			contmarker2->setVisible(false);
					
		contline->setValue(w.at(upperCpointi),1.0);
		
		marker1->setValue(w.at(lowerb1i),newd.at(lowerCpointi));
		marker1->setVisible(true);
		marker3->setValue(w.at(lowerb2i),newd.at(lowerCpointi));
		marker3->setVisible(true);
		marker2->setValue(w.at(upperb1i),newd.at(upperCpointi));
		marker2->setVisible(true);
		marker4->setValue(w.at(upperb2i),newd.at(upperCpointi));
		marker4->setVisible(true);
	}	
	
	contline->setVisible(true);
	
	spinbox1->setRange(-5.0*maxrc,5.0*maxrc);
 	spinbox2->setRange(-5.0*minrc,5.0*minrc);  
 	
 	spinbox1->setSingleStep((maxrc - minrc)/100.0);
 	spinbox2->setSingleStep((maxrc - minrc)/100.0);   
 		
	spinbox1->setValue(maxrc + 0.05*maxrc);
 	spinbox2->setValue(minrc - 0.05*minrc);   	
 	
	rcdata->setSamples(&w[0],&newd[0],w.size());

	rcdata->attach(plot);
	rcdata->setVisible(true);
	
	plot->replot();
	pzoomer->setZoomBase();
	}

}

void PlotDialog::calculate()
{
	QString str1 = inputfilelineedit->text();
	QByteArray ba = str1.toLocal8Bit();
	filename = ba.data();

	QString str;
	str = entry->toPlainText();

	QStringList list = str.split(",", QString::SkipEmptyParts);
	
	if(list.size() < 2)
		return;
	
	if(!strdisplay->isEmpty())
		strdisplay->clear();
	
	if ( numOfChannels != w.size() )
	{
		strdisplay->append("File read error");
		display->appendPlainText(*strdisplay);
		return;
	}
	numOfBands = 0;
	// array to hold lower and upper bounds
	// lowerb2 and upperb2 are used when ranges are defined.
	double lowerb1[MAX_NUMBER_OF_BANDS], upperb1[MAX_NUMBER_OF_BANDS];
	double lowerb2[MAX_NUMBER_OF_BANDS], upperb2[MAX_NUMBER_OF_BANDS];
	
	// Read in continuum points or ranges
	int i = 0;
	while(i < list.size())
	{
		
		if(usingranges == 0)
		{
			if(list.at(i).toDouble() != 0 && list.at(i+1).toDouble() != 0)
			{
				lowerb1[numOfBands] = (list.at(i)).toDouble();
				upperb1[numOfBands] = (list.at(i+1)).toDouble();
				numOfBands++;
				i+=2;
			}
			else
			{
				// This shouldn't happen. 
				cout << "Bad command line arguments!" << endl;
				return;
			}
		}
		else
		{
			if(list.at(i).toDouble() != 0 && list.at(i+1).toDouble() != 0 && list.at(i+2).toDouble() != 0 && list.at(i+3).toDouble() != 0)
			{
				lowerb1[numOfBands] = list.at(i).toDouble();
				upperb1[numOfBands] = list.at(i+1).toDouble();
				lowerb2[numOfBands] = list.at(i+2).toDouble();
				upperb2[numOfBands] = list.at(i+3).toDouble();
				numOfBands++;
				i+=4;
			}
			else
			{
				// This shouldn't happen. 
				cout << "Bad command line arguments!" << endl;
				return;
			}
		}
	}
	// Read file into arrays for wavelengths, data, and errors 
	double wavelength[numOfChannels],data[numOfChannels],error[numOfChannels];
	readFile(filename,wavelength,data,error,numOfChannels);
	if(usingranges == 0)
	{
	    int lowerindex[numOfBands], upperindex[numOfBands];
	
		// Convert input arrays of wavelength boundary to arrays of channel numbers.
		matchToChannels( wavelength, lowerb1, lowerindex, numOfBands, numOfChannels);
		matchToChannels( wavelength, upperb1, upperindex, numOfBands, numOfChannels);
	
				// Calculates band min, band depth, fwhm, asymmetry and adds them to display.
		for(i = 0; i < numOfBands; i++)
		{

			calcParameters(wavelength, data, lowerindex[i], upperindex[i], numOfChannels, &bandMin, &bandDepth, &FWHM, &asym);
			
			strdisplay->append("File: ");
			strdisplay->append(filename);
			strdisplay->append("\n");
			strdisplay->append("Wavelengths: ");
			strutil->setNum(wavelength[lowerindex[i]]);
			strdisplay->append(strutil);
			strdisplay->append(" - ");
			strutil->setNum(wavelength[upperindex[i]]);
			strdisplay->append(strutil);
			//strdisplay->append("\n");
			
			strdisplay->append(" (Channels: ");
			strutil->setNum(lowerindex[i] + 1);
			strdisplay->append(strutil);
			strdisplay->append(" - ");
			strutil->setNum(upperindex[i] + 1);
			strdisplay->append(strutil);
			strdisplay->append(")\n");
			
			strdisplay->append("Minimum\t\tDepth   \t\tFWHM    \t\tAsymmetry\n");
			
			strbandmin->setNum(bandMin);
			strdisplay->append(strbandmin);
			strdisplay->append("\t\t");
			
			strbanddepth->setNum(bandDepth);
			strdisplay->append(strbanddepth);
			strdisplay->append("\t\t");
			
			strfwhm->setNum(FWHM);
			strdisplay->append(strfwhm);
			strdisplay->append("\t\t");
			
			strasym->setNum(asym);
			strdisplay->append(strasym);
			strdisplay->append("\n");
			
		}
	
	}
	else
	{
	// indicies of channels corresponding to the continuum points.
	int lowerCpointi[numOfBands], upperCpointi[numOfBands];
	
	// y-values of the continuum points. (Average of values within range)
	double lowerCpointval[numOfBands], upperCpointval[numOfBands];
	
	// Fills the lowerCpointi and lowerCpointval arrays
	findCpoint(wavelength, data, lowerb1, upperb1, lowerCpointi, lowerCpointval, numOfBands, numOfChannels, 0);
	
	// Fills the upperCpointi and upperCpointval arrays
	findCpoint(wavelength, data, lowerb2, upperb2, upperCpointi, upperCpointval, numOfBands, numOfChannels, 1);

		// Calculates band min, band depth, fwhm, asymmetry and adds them to display.
		for(i = 0; i < numOfBands; i++)
		{

		calcParameters2(wavelength, data, lowerCpointval[i], upperCpointval[i], lowerCpointi[i], upperCpointi[i], numOfChannels, &bandMin, &bandDepth, &FWHM, &asym);	
		
			strdisplay->append("File: ");
			strdisplay->append(filename);
			strdisplay->append("\n");
			
			strdisplay->append("Continuum Point Ranges: ");
			strutil->setNum(lowerb1[i]);
			strdisplay->append(strutil);
			strdisplay->append(" - ");
			strutil->setNum(lowerb2[i]);
			strdisplay->append(strutil);
			strdisplay->append(",  ");
			strutil->setNum(upperb1[i]);
			strdisplay->append(strutil);
			strdisplay->append(" - ");
			strutil->setNum(upperb2[i]);
			strdisplay->append(strutil);
			strdisplay->append("\n");
			
			strdisplay->append("Feature wavelengths: ");
			strutil->setNum(wavelength[lowerCpointi[i]]);
			strdisplay->append(strutil);
			strdisplay->append(" - ");
			strutil->setNum(wavelength[upperCpointi[i]]);
			strdisplay->append(strutil);
			//strdisplay->append("\n");
			
			strdisplay->append(" (Channels: ");
			strutil->setNum(lowerCpointi[i] + 1);
			strdisplay->append(strutil);
			strdisplay->append(" - ");
			strutil->setNum(upperCpointi[i] + 1);
			strdisplay->append(strutil);
			strdisplay->append(")\n");
			
			strdisplay->append("Minimum\t\tDepth   \t\tFWHM    \t\tAsymmetry\n");
			
			strbandmin->setNum(bandMin);
			strdisplay->append(strbandmin);
			strdisplay->append("\t\t");
			
			strbanddepth->setNum(bandDepth);
			strdisplay->append(strbanddepth);
			strdisplay->append("\t\t");
			
			strfwhm->setNum(FWHM);
			strdisplay->append(strfwhm);
			strdisplay->append("\t\t");
			
			strasym->setNum(asym);
			strdisplay->append(strasym);
			strdisplay->append("\n");
		}
	}
	bandcenterline->setValue(bandMin,minrc);
	actualminmarker->setValue(minrcx,minrc);
	
	if(showbandcenterline)
		bandcenterline->setVisible(true);
	
	if(showactualminmarker)	
		actualminmarker->setVisible(true);
		
	plot->replot();
	display->appendPlainText(*strdisplay);
}

// Point selection signal.
void PlotDialog::pointRegister(const QPointF &pos)
{
	if(!data->isVisible() && !rcdata->isVisible())
		return;
	if(usingranges == 0)
	{
		if(marker1->isVisible() && marker3->isVisible())
		{
			marker1->setValue(pos);
			marker3->setVisible(false);

			entry->clear();
		}
		else if(marker1->isVisible())
		{
			marker3->setValue(pos);
			marker3->setVisible(true);
			selectbox->setChecked(false);
		}
		else
		{
			marker1->setValue(pos);
			marker1->setVisible(true);
		}
	}
	else
	{
		if(marker1->isVisible() && marker2->isVisible() && marker3->isVisible() && marker4->isVisible())
		{
			marker1->setValue(pos);
			marker2->setVisible(false);
			marker3->setVisible(false);
			marker4->setVisible(false);
			entry->clear();
		}
		else if(marker1->isVisible() && marker2->isVisible() && marker3->isVisible())
		{
			marker4->setValue(pos);
			marker4->setVisible(true);
			selectbox->setChecked(false);
		}
		else if(marker1->isVisible() && marker2->isVisible())
		{
			marker3->setValue(pos);
			marker3->setVisible(true);
		}
		else if(marker1->isVisible() )
		{
			marker2->setValue(pos);
			marker2->setVisible(true);
		}
		else
		{
			marker1->setValue(pos);
			marker1->setVisible(true);
		}
	}
	plot->replot();
	strutil->setNum(pos.x());
	strutil->append(",");
	entry->insertPlainText(*strutil);
}

// Reset the axes and axis ranges
void PlotDialog::resetaxes()
{
	if(xmin != 0 || xmax != 0 || ymin != 0 || ymax != 0)
	{	

		if(rcdata->isVisible())
	 	{
	 		spinbox1->setRange(-5.0*maxrc,5.0*maxrc);
		 	spinbox2->setRange(-5.0*minrc,5.0*minrc);  
		 	
		 	spinbox1->setSingleStep((maxrc - minrc)/100.0);
		 	spinbox2->setSingleStep((maxrc - minrc)/100.0);   
		 		
			spinbox1->setValue(maxrc + 0.05*maxrc);
		 	spinbox2->setValue(minrc - 0.05*minrc);   
	 	}
		else if(data->isVisible())
		{
			spinbox1->setRange(ymin - 0.2*ymin,ymax + 0.2*ymax);
		 	spinbox2->setRange(ymin - 0.2*ymin,ymax + 0.2*ymax);  

		 	
		 	spinbox1->setSingleStep((ymax - ymin)/100.0);
		 	spinbox2->setSingleStep((ymax - ymin)/100.0);  

		 	
			spinbox1->setValue(ymax);
		 	spinbox2->setValue(ymin);   

	 	}
	 	spinbox3->setRange(xmin - 0.2*xmin,xmax + 0.2*xmax);
	 	spinbox4->setRange(xmin - 0.2*xmin,xmax + 0.2*xmax);		 	
	 	spinbox3->setSingleStep((xmax - xmin)/100.0);
	 	spinbox4->setSingleStep((xmax - xmin)/100.0);  		 	
	 	spinbox3->setValue(xmin);
	 	spinbox4->setValue(xmax); 
	 	plot->replot(); 
 	}
}

// Clears the input and markers
void PlotDialog::cleartext()
{
	marker1->setVisible(false);
	marker2->setVisible(false);
	marker3->setVisible(false);
	marker4->setVisible(false);
	//contline->setVisible(false);
	contmarker1->setVisible(false);
	contmarker2->setVisible(false);
	plot->replot();
	entry->clear();
}

void PlotDialog::clearoutput()
{
	display->clear();
}

void PlotDialog::printtostd()
{
		*strutil = display->toPlainText();
		QByteArray ba = strutil->toLocal8Bit();
		char *info = ba.data();
		cout << endl;
		cout << info << endl;
}

void PlotDialog::printPlotDataToFile()
{
	QStringList fileNames;
    QString Qoutputfilename; 
    savedialog->setDirectory(filedialog->directory());
	savedialog->show();   
	
	if (savedialog->exec())
	{
		fileNames = savedialog->selectedFiles();
		Qoutputfilename = fileNames.at(0);
		QByteArray ba = Qoutputfilename.toLocal8Bit();
		char *outputfilename = ba.data();
		
		ofstream fs;
		fs.open(outputfilename,ios_base::app);
		int k;
		fs << fixed;
		if(data->isVisible())
		{
			for(k = 0; k < (int)d.size(); k++)
				fs << w.at(k) << "\t" << d.at(k) << endl;
		}
		else if(rcdata->isVisible())
		{
			for(k = 0; k < (int)newd.size(); k++)
				fs << w.at(k) << "\t" << newd.at(k) << endl;
		}
		else
		{
			QMessageBox msg;
			msg.setText("Error exporting plot data.");
			msg.setInformativeText("Make sure plot data exists.");
			msg.exec();
			return;
		}
     	fs.close();
	}
}

void PlotDialog::printtofile()
{

    QStringList fileNames;
    QString Qoutputfilename; 
    savedialog->setDirectory(filedialog->directory());
	savedialog->show();   
	
	if (savedialog->exec())
	{
		fileNames = savedialog->selectedFiles();
		Qoutputfilename = fileNames.at(0);
		QByteArray ba = Qoutputfilename.toLocal8Bit();
		char *outputfilename = ba.data();
		
		*strutil = display->toPlainText();
		QByteArray ba2 = strutil->toLocal8Bit();
		char *info = ba2.data();
		ofstream fs;
		fs.open(outputfilename,ios_base::app);
     	fs << info << endl;
     	fs.close();
	}
         
}
// Resets nearly everything
void PlotDialog::reset()
{
	if(xmin != 0 && xmax != 0 && ymin != 0 && ymax != 0)
	{
		marker1->setVisible(false);
		marker2->setVisible(false);
		marker3->setVisible(false);
		marker4->setVisible(false);
		contline->setVisible(false);
		contmarker1->setVisible(false);	
		contmarker2->setVisible(false);	
		bandcenterline->setVisible(false);
		actualminmarker->setVisible(false);
					
		spinbox1->setRange(ymin - 0.2*ymin,ymax + 0.2*ymax);
	 	spinbox2->setRange(ymin - 0.2*ymin,ymax + 0.2*ymax);  
	 	spinbox3->setRange(xmin - 0.2*xmin,xmax + 0.2*xmax);
	 	spinbox4->setRange(xmin - 0.2*xmin,xmax + 0.2*xmax);
	 	
	 	spinbox1->setSingleStep((ymax - ymin)/100.0);
	 	spinbox2->setSingleStep((ymax - ymin)/100.0);  
	 	spinbox3->setSingleStep((xmax - xmin)/100.0);
	 	spinbox4->setSingleStep((xmax - xmin)/100.0);  
	 	
		spinbox1->setValue(ymax);
	 	spinbox2->setValue(ymin);   
	 	spinbox3->setValue(xmin);
	 	spinbox4->setValue(xmax); 
	 		
		// If something is plotted, get rid of it. 
		data->setVisible(false);
		rcdata->setVisible(false);
	 	plot->replot(); 

	 	resetbutton->setEnabled(false);
		calcbutton->setEnabled(false);
		rcbutton->setEnabled(false);
		clearbutton->setEnabled(false);
	 	clearoutputbutton->setEnabled(false);
	 	tofilebutton->setEnabled(false);
	 	tostdoutbutton->setEnabled(false);
 	}
 	entry->clear();
 	display->clear();
}

// Quits the program
void PlotDialog::quit()
{
	reject();
}

